/*
 * ctimer.c
 *
 *  Created on: 2017-4-8
 *      Author: chenshisheng
 */

#include "ctimer.h"
#include "utils.h"
//#include "active.h"

#define CTIMER_FLAG_INITIALIZED (0x01)
#define CTIMER_FLAG_STOPED      (0x01 << 1)
#define CTIMER_FLAG_READY       (0x01 << 2)

#ifndef CMSIS_OS
#include "mlist.h"

#define TIM_FREQ CTIMER_TICK_CLK
#define TIM_INTERVAL (1000 / TIM_FREQ)

#define SYSTICK_CLK 11059200UL

// 软件定时器链表
LIST(_list);

void Ctimer_Init(void)
{
    uint32_t ticks = SYSTICK_CLK / TIM_FREQ;

    list_init( _list);

    SysTick->LOAD = ticks - 1;
    SysTick->VAL = 0;
    BIT_SET(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
    Main_SetPriority(SysTick_IRQn, 1, 0);
}

/**
 * @brief 硬件定时器的一次中断为一次Tick，每个Tick都递增链表内的软件定时器计数，
 *        若计数到达目标计数值就将其回调函数发到消息队列，交由消息队列服务函数在
 *        main()函数内执行回调函数(在Ctimer_Fire()函数内执行).
 */
static inline void _OnTickUpdate(unsigned int ms)
{
    Ctimer_t *timer, *curTimer;

    if(ms == 0)
    {
        return;
    }

    timer = list_head(_list);
    while(timer != NULL)
    {
        curTimer = timer;
        timer = list_item_next(timer);
        if(curTimer->flags & CTIMER_FLAG_PAUSE)
        {
            continue;
        }

        if((curTimer->flags & CTIMER_FLAG_ONCE) && (curTimer->flags & CTIMER_FLAG_READY))
        {
            continue;
        }

        curTimer->counter += ms;
        if(curTimer->counter >= curTimer->interval)
        {
            curTimer->counter = 0;
            if(curTimer->flags & CTIMER_FLAG_REALTIME)
            {
                curTimer->callback(curTimer->arg);
            }
            else
            {
                BIT_SET(curTimer->flags, CTIMER_FLAG_READY);
            }
        }
    }
}

void Ctimer_Service(void)
{
    Ctimer_t *timer, *curTimer;

    ENTER_CRITICAL();
    timer = list_head(_list);
    EXIT_CRITICAL();

    while(timer != NULL)
    {
        curTimer = timer;
        ENTER_CRITICAL();
        timer = list_item_next(timer);
        EXIT_CRITICAL();
        if(! Ctimer_IsActive(curTimer))
        {
            continue;
        }

        if(curTimer->flags & CTIMER_FLAG_READY)
        {
            ENTER_CRITICAL();
            BIT_CLR(curTimer->flags, CTIMER_FLAG_READY);
            if(curTimer->flags & CTIMER_FLAG_ONCE)
            {
                Ctimer_Stop(curTimer);
            }
            EXIT_CRITICAL();

            curTimer->callback(curTimer->arg);
        }
    }
}

void SysTick_Handler(void)
{
    _OnTickUpdate(TIM_INTERVAL);
}

/**
 * @brief 启动一个软件定时器，要求必须使用全局型的定时器变量，
 *        启动后回调函数将被循环触发
 * @param timer 指向全局型的定时器变量
 * @param intervalMs 定时间隔，单位毫秒
 * @param cb    定时到达后被调用的回调函数
 * @param flags 标志集
 * @return 0  启动成功
 *         -1 失败
 */
int Ctimer_Start(Ctimer_t *timer,
        unsigned int intervalMs,
        Callback_t cb,
        unsigned int flags,
        void *arg)
{

    assert_param(Utils_IsGlobalVariable(timer));

    ENTER_CRITICAL();
    timer->counter = 0;
    timer->interval = intervalMs;
    timer->flags = flags | CTIMER_FLAG_INITIALIZED;
    timer->arg = arg;
    timer->callback = cb;

    list_add(_list, timer);

    if(timer->flags & CTIMER_FLAG_FIRE_ON_START)
    {
        if(timer->flags & CTIMER_FLAG_REALTIME)
        {
            timer->callback(timer->arg);
        }
        else
        {
//            MsgQueue_CallLater(timer->callback, timer->arg);
            BIT_SET(timer->flags, CTIMER_FLAG_READY);
        }
    }
    EXIT_CRITICAL();

    return 0;
}

#if 1
int Ctimer_Restart(Ctimer_t *timer, unsigned int intervalMs)
{
    if(! (timer->flags & CTIMER_FLAG_INITIALIZED))
    {
        return -1;
    }

    ENTER_CRITICAL();
    timer->counter = 0;
    timer->interval = intervalMs;
    if(timer->flags & CTIMER_FLAG_STOPED)
    {
        BIT_CLR(timer->flags, CTIMER_FLAG_STOPED);
        list_add(_list, timer);
    }
    EXIT_CRITICAL();

    return 0;
}
#endif

int Ctimer_Reset(Ctimer_t *timer)
{
    if((! (timer->flags & CTIMER_FLAG_INITIALIZED)) ||
            (timer->flags & CTIMER_FLAG_STOPED))
    {
        return -1;
    }

    timer->counter = 0;
    if(timer->flags & CTIMER_FLAG_PAUSE)
    {
        BIT_CLR(timer->flags, CTIMER_FLAG_PAUSE);
    }

    return 0;
}

int Ctimer_Stop(Ctimer_t *timer)
{
    if(!(timer->flags & CTIMER_FLAG_INITIALIZED))
    {
        return -1;
    }

    ENTER_CRITICAL();
    list_remove(_list, timer);
    BIT_SET(timer->flags, CTIMER_FLAG_STOPED);
    BIT_CLR(timer->flags, CTIMER_FLAG_READY);
    EXIT_CRITICAL();

    return 0;
}

int Ctimer_IsStarted(const Ctimer_t *timer)
{
    return (timer->flags & CTIMER_FLAG_INITIALIZED) &&
            ! (timer->flags & CTIMER_FLAG_STOPED);
}

int Ctimer_Pause(Ctimer_t *timer, bool isPause)
{
    if(!(timer->flags & CTIMER_FLAG_INITIALIZED))
    {
        return -1;
    }

    if(isPause)
    {
        BIT_SET(timer->flags, CTIMER_FLAG_PAUSE);
    }
    else
    {
        BIT_CLR(timer->flags, CTIMER_FLAG_PAUSE);
    }

    return 0;
}

bool Ctimer_IsPaused(const Ctimer_t *timer)
{
    return Ctimer_IsStarted(timer) && (timer->flags & CTIMER_FLAG_PAUSE);
}

bool Ctimer_IsActive(const Ctimer_t *timer)
{
    return Ctimer_IsStarted(timer) && ! (timer->flags & CTIMER_FLAG_PAUSE);
}

#else
void Ctimer_Init(void)
{

}

/**
 * @brief 启动一个软件定时器，要求必须使用全局型的定时器变量，
 *        启动后回调函数将被循环触发
 * @param timer 指向全局型的定时器变量
 * @param intervalMs 定时间隔，单位毫秒
 * @param cb    定时到达后被调用的回调函数
 * @param flags 标志集
 * @return 0  启动成功
 *         -1 失败
 */
int Ctimer_Start(Ctimer_t *timer,
        unsigned int intervalMs,
        Ctimer_Callback_t callback,
        unsigned int flags,
        void *arg)
{
    assert_param(Utils_IsGlobalVariable(timer));
    if((timer->flags & CTIMER_FLAG_INITIALIZED) && (timer->id != NULL))
    {
        osTimerDelete(timer->id);
    }

    const osTimerAttr_t attr = {NULL, 0, &timer->_st, sizeof(timer->_st)};
    osTimerType_t type = (flags & CTIMER_FLAG_ONCE) ? osTimerOnce : osTimerPeriodic;

    timer->id = osTimerNew(callback, type, arg, &attr);
    if(timer->id == NULL)
    {
        return -2;
    }

    timer->flags = flags | CTIMER_FLAG_INITIALIZED;
    timer->interval = intervalMs;
    return osTimerStart(timer->id, intervalMs);
}

int Ctimer_Stop(Ctimer_t *timer)
{
    int ret;

    if((timer->flags & CTIMER_FLAG_INITIALIZED) == 0)
    {
        return -1;
    }

    ret = osTimerStop(timer->id);
    SET_BIT(timer->flags, CTIMER_FLAG_STOPED);
    return ret;
}

int Ctimer_IsStarted(Ctimer_t *timer)
{
    return (timer->flags & CTIMER_FLAG_INITIALIZED) &&
            osTimerIsRunning(timer->id);
}

int Ctimer_Restart(Ctimer_t *timer, unsigned int intervalMs)
{

    if((! (timer->flags & CTIMER_FLAG_INITIALIZED)) ||
            (timer->flags & CTIMER_FLAG_STOPED))
    {
        return -1;
    }

    timer->interval = intervalMs;
    return osTimerStart(timer->id, intervalMs);
}

int Ctimer_Reset(Ctimer_t *timer)
{

    if((! (timer->flags & CTIMER_FLAG_INITIALIZED)) ||
            (timer->flags & CTIMER_FLAG_STOPED))
    {
        return -1;
    }

    return osTimerStart(timer->id, timer->interval);
}
#endif

